package com.ld.security.common.core.util;

import cn.hutool.core.lang.Console;
import com.ld.security.common.core.base.SuperPo;
import com.ld.security.common.core.base.SuperVo;
import com.ld.security.common.core.base.column.ListString;
import com.ld.security.common.core.base.column.SuperColumn;
import com.ld.security.common.core.constant.CSuperConstant;
import com.ld.security.common.core.constant.LangConstant;
import com.ld.security.common.core.exception.ApiException;
import lombok.Data;
import lombok.SneakyThrows;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

public class ReflectionUtil {

	private static final String set_prefix = "set";

	private static final String get_prefix = "get";

	private static final String is_prefix = "is";

	public static final String sp_prefix = "\\.";

	private static  boolean methodWhere(Method method,Class... clazz){
		int i = 0;
		for (Class<?> aClass : method.getParameterTypes()) {
			if(!aClass.isAssignableFrom(clazz[i++])){
				return false;
			}
		}
		return true;
	}


	@SneakyThrows
	public static Method findMethod(Class clazz,String name,Class... paramsClass){
		for (Method method : clazz.getMethods()) {
			if(method.getName().equals(name)){
				if(methodWhere(method,paramsClass)){
					return method;
				}
			}
		}
		return  null;
	}


	@SneakyThrows
	public static Object invokeMethod(Object obj,String name,Object... params) {

		Class[] clazzs = new Class[params.length];
		int i  = 0;
		for (Object param : params) {
			clazzs[i++] = param.getClass();
		}
		Method method =  findMethod(obj.getClass(),name,clazzs);
		method.setAccessible(true);
		try{
			return method.invoke(obj,params);
		}catch (Exception e){
			e.printStackTrace();
		}
		return null;
	}



		/**
         * 实体类型转型
         * @param val
         * @param cla
         * @param <E>
         * @return
         */
	public static <E> E clone(Object val,Class<E> cla,Class<?>... clazz){
		return JsonUtil.clone(val,cla,clazz);
	}

	/**
	 * 通类型对象值拷贝
	 * @param source 数据源对象
	 * @param target 目标对象
	 * @param <E>
	 * @return
	 */
	public static <E> E copy(E source,E target) {

		Class clazz = source.getClass();
		for (Field field : ReflectionUtil.getAllDeclaredFields(clazz)) {

			Object v =  ReflectionUtil.invokeGetter(target,field.getName());
			if(isNotNull(v)){
				continue;
			}
			Object v2 =  ReflectionUtil.invokeGetter(source,field.getName());
			if(v2 != null){
				invokeSetter(target,field.getName(),v2);
			}

		}
		return target;
	}

	public static Field findField(Class clazz,String name){
		return  ReflectionUtils.findField(clazz,name);
	}

		/**
         *  对字段预处理
         * @param obj
         * @param aClazz
         * @param f
         * @param <E>
         */
	public static <E extends Annotation> void applyAllDeclaredFields(Object obj,Class<E> aClazz, FieldFunc<E> f) {

		for (Field field : getAllDeclaredFields(obj.getClass())) {
			E anno = AnnotationUtils.findAnnotation(field,aClazz);
			if(anno == null){
				Method method =  getGetMethod(obj.getClass(),field.getName());
				anno =  AnnotationUtils.findAnnotation(method,aClazz);
			}
			if(anno == null){
				continue;
			}
			Object val =  invokeGetter(obj,field.getName());

			f.run(anno,field.getName(),val);
		}

	}

	/**
	 * 得到所有字段
	 * @param clazz
	 * @return
	 */
	public static List<Field> getAllDeclaredFields(Class<?> clazz) {
		List<Field> list = new LinkedList<>();
		while(clazz != null) {
			for(Field field:clazz.getDeclaredFields()) {
				if(Modifier.isStatic(field.getModifiers())){
					continue;
				}
				list.add(field);
			}
			clazz = clazz.getSuperclass();
		}
		return list;
	}


	private static Method getGetMethod(Class clazz,String name){
		String methodName =get_prefix + StringUtil.toUpperCaseFirstOne(name);
		Method method = ReflectionUtils.findMethod(clazz,methodName);

		return method;
	}
	private static Method getSetMethod(Class clazz,String name){
		String methodName =set_prefix + StringUtil.toUpperCaseFirstOne(name);
		for (Method method : clazz.getMethods()) {
			if(method.getName().equals(methodName)){
				return method;
			}
		}


		return null;
	}




	public static <E> E newInstance(Class<E> cla){
		try{
			return cla.newInstance();
		}catch (Exception e){
			throw new RuntimeException("实例化异常:"+cla);
		}

	}

  public static <E> E invokeGetter(Object obj, String[] names) {
		return invokeGetter(obj,Arrays.asList(names));
  }
		/**
         * 调用Getter方法.
         * 支持多级，如：对象名.对象名.方法
         */
	public static <E> E invokeGetter(Object obj, List<String> names) {
		Object object = obj;
		for (String name : names){
			if(object == null){
				ApiException.throw400("异常获取值:"+names);
			}
			if(object.getClass().isArray()){
				Object[] args =  (Object[])object;
				object = args[Integer.parseInt(name)];
			}else if(object instanceof List){
				List list = (List) object;
				object= list.get(Integer.parseInt(name));
			} else if(object instanceof  Map){
				Map map = (Map)object;
				object = map.get(name);
			}else{
				Method method = getGetMethod(object.getClass(),name);
				if(method == null){
					ApiException.throw400(object.getClass()+"异常属性"+name);

				}
				method.setAccessible(true);
				object = ReflectionUtils.invokeMethod(method,object);
			}

		}
		return (E)object;
	}

	/**
	 * 调用Getter方法.
	 * 支持多级，如：对象名.对象名.方法
	 */
	public static <E> E invokeGetter(Object obj, String propertyName) {
		String[] names = propertyName.split(sp_prefix);
		return (E)invokeGetter(obj,names);
	}
	/**
	 * 调用Setter方法, 仅匹配方法名。
	 * 支持多级，如：对象名.对象名.方法
	 */
	public static void invokeSetter(Object obj, String propertyName, Object value) {
		Object object = obj;
		String[] names = propertyName.split(sp_prefix);
		String key = names[names.length-1];
		if(names.length >=2){
			String[] keys = new String[names.length - 1];
			for (int i = 0;i<names.length - 1;i++){
				keys[i]=names[i];
			}
			object = invokeGetter(obj,keys);
		}
		if(object.getClass().isArray()){
			Object[] args =  (Object[])object;
			args[Integer.parseInt(key)] = value;
		}else if(object instanceof List){
			List list = (List) object;
			list.add(Integer.parseInt(key),value);
		} else if(object instanceof  Map){
			Map map = (Map)object;
			map.put(key,value);
		}else{
			Method method=getSetMethod(object.getClass(),key);
			if(method == null){
				ApiException.throw400(object.getClass()+"异常属性"+propertyName);
			}
			method.setAccessible(true);
			if(!method.getParameterTypes()[0].isAssignableFrom(value.getClass())){
				ApiException.throw400("类型参数异常");

			}

			ReflectionUtils.invokeMethod(method,object,value);

		}

	}




	public static boolean isNotNull(Object val) {
	return !isNull(val);
	}
		/**
         * 判断对象是否空
         * @param val
         * @return
         */
	public static boolean isNull(Object val){
		if(val instanceof Collection){
			Collection col = (Collection) val;
			if(!col.isEmpty()){
				return false;
			}
		}else if(val instanceof Map){
			Map map = (Map) val;
			if(map.keySet().size() > 0){
				return false;
			}
		}else if(val instanceof String){
			boolean b= StringUtil.isNull(val.toString());
			if(!b){
				return false;
			}
		}else if(val instanceof Number){
			return false;
		}
		else if(val instanceof SuperPo){
			for (Field field : ReflectionUtil. getAllDeclaredFields(val.getClass())) {
				Object v = ReflectionUtil.invokeGetter(val,field.getName());
				if(!isNull(v)){
					return  false;
				}
			}
		}else if(val instanceof CSuperConstant.EnSuperEnum){
			return false;
		}else if(val != null){
			return false;
		}
		return true;
	}

	public static void fill(Object obj){

		for (Field field : ReflectionUtil.getAllDeclaredFields(obj.getClass())) {

			Object value = ReflectionUtil.invokeGetter(obj,field.getName());
			if(value != null) {
				continue;
			}
			Class clazz = field.getType();
			if(Integer.class.isAssignableFrom(clazz)) {
				value=0;
			}else if(Double.class.isAssignableFrom(clazz)) {
				value=0.0;
			}else if(Boolean.class.isAssignableFrom(clazz)) {
				value= false;
			}else if(Date.class.isAssignableFrom(clazz)) {
				value= new Date();
			}else if(String.class.isAssignableFrom(clazz)) {
				value="";
			}else if(SuperColumn.class.isAssignableFrom(clazz)){
				value = ReflectionUtil.newInstance(clazz);
				if(value instanceof ListString){
					ListString listString = (ListString)value;
					listString.add("0");
				}
			}else if(clazz.isEnum()){
				Object[] as =  clazz.getEnumConstants();
				if(as.length > 0){
					value =as[0];
				}
			}else if(List.class.isAssignableFrom(clazz)){
				value = new LinkedList<>();
			}else if(Map.class.isAssignableFrom(clazz)){
				value = new HashMap<>();
			}else{
				value = ReflectionUtil.newInstance(field.getType());
				if(value instanceof SuperVo){
					fill(value);
				}
			}
			if(value != null){
				ReflectionUtil.invokeSetter(obj,field.getName(), value);
			}

		}
	}


}